package com.example.qxfw.cshx.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dmgis.entity.DmMapPoint;
import com.dmgis.service.DmServiceConnector;
import com.dmgis.weblib.MapCommon;
import com.example.qxfw.common.entity.YuLinCityPoints;
import com.example.qxfw.common.entity.qx.TownshipForecast;
import com.example.qxfw.common.entity.zy.*;
import com.example.qxfw.common.service.impl.FileRequestService;
import com.example.qxfw.common.util.DateUtil;
import com.example.qxfw.common.util.DocxUtil;
import com.example.qxfw.common.util.TxtFileManager;
import com.example.qxfw.cshx.entity.CSHX_yz;
import com.example.qxfw.cshx.entity.CityFire;
import com.example.qxfw.cshx.mapper.CcshxImpDotMapper;
import com.example.qxfw.cshx.mapper.CshxSettingMapper;
import com.example.qxfw.cshx.mapper.CshxYzMapper;
import com.example.qxfw.cshx.mapper.CshxZsybMapper;
import com.example.qxfw.cshx.service.FireWarningService;
import com.example.qxfw.mongodb.hy.entity.HyDocFile;
import com.example.qxfw.mongodb.hy.service.DocFileService;
import com.example.qxfw.ybzz.mapper.BaseProductMapper;
import com.example.qxfw.ybzz.mapper.TourFcstMapper;
import com.example.qxfw.ybzz.mapper.TownshipForecastMapper;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

import static com.example.qxfw.common.util.DocxUtil.*;

@Service
public class CshxHxyjServiceImpl implements FireWarningService {

    private static final String pluginClassFullName = "contourservice";

    private static final String methodName = "GetInterpolationWork";
    @Autowired
    private BaseProductMapper baseProductMapper;
    @Autowired
    private CshxZsybMapper cshxZsybMapper;
    @Autowired
    private CshxSettingMapper cshxSettingMapper;
    @Autowired
    private TourFcstMapper tourFcstMapper;
    @Autowired
    private CshxYzMapper cshxYzMapper;
    @Autowired
    private TownshipForecastMapper townshipForecastMapper;

    @Value("${txt.file.txtIp}")
    private String txtIp;

    @Value("${txt.file.txtPort}")
    private String txtPort;

    @Value("${server.servlet.context-path}")
    private String path;

    @Value("${dmgis.ip}")
    private String serverName;

    @Value("${dmgis.port}")
    private String port;

    @Autowired
    private TxtFileManager txtFileManager;

    @Value("${filePath.active}")
    private String active;

    @Value("${county}")
    private String county;

    @Autowired
    private CcshxImpDotMapper ccshxImpDotMapper;

    @Qualifier("mongoSecondTemplate")
    @Autowired
    private MongoTemplate mongoTemplate;

    List<CityFire> citys = new ArrayList<>();
    String timeChar = "08";
    FileRequestService ms = new FileRequestService();

    @Override
    public List<CshxZsyb> fireDangerForecasting(String time, String timeChar) {
        List<CshxZsyb> insertListData = new ArrayList<>();
        LocalDateTime localDateTime = DateUtil.stringToLocalDateTime(time);
        Timestamp timestamp = DateUtil.localDateTimeToTimestamp(localDateTime);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");

        // 获取当前日期和时间
        Date currentDate = new Date();
        // 格式化当前时间为指定格式的字符串
        String formattedDate = sdf.format(currentDate);
        LocalDateTime localDateTime1 = DateUtil.stringToLocalDateTime(formattedDate);
        Timestamp timestamp1 = DateUtil.localDateTimeToTimestamp(localDateTime1);



        CalcSmallScaleStationFactor(timeChar, timestamp);
        CalcSpecialStationFactor(timeChar, timestamp);
        if (citys.size() == 0) {
            System.out.println("没有该日期的预报数据");
        }
        try {
            int delete = cshxZsybMapper.delete(new LambdaQueryWrapper<CshxZsyb>()
                    .eq(CshxZsyb::getForcastdate, timestamp));
            System.out.println("删除了：" + delete);

            List<CSHX_yz> yzList = loadYz(localDateTime);//获因取子
            System.err.println("获因取子 : " + yzList.size());
            System.err.println("citys : " + citys.size());
            for (CityFire city : citys) {
                CshxZsyb insertData = new CshxZsyb();
                int sumYz = 0;
                double valrel = city.getYbMinRelHumidity();
                double valtemp = city.getYbMaxTemp();
                double valwind = city.getYbMaxWindS();
                double valRain = city.getYbRain();
                int valno = city.getNoRainDay();
                for (CSHX_yz yz : yzList) {
                    if ("日最高气温".equals(yz.getElement()) && valtemp >= yz.getMin() && valtemp <= yz.getMax()) {
                        city.setYbMaxTemp(yz.getYz());
                    } else if ("日最小相对湿度".equals(yz.getElement()) && valrel >= yz.getMin() && valrel <= yz.getMax()) {
                        city.setYbMinRelHumidity(yz.getYz());
                    } else if ("日最大风速".equals(yz.getElement()) && valwind >= yz.getMin() && valwind <= yz.getMax()) {
                        city.setYbMaxWindS(yz.getYz());
                    } else if ("连续无降水日数".equals(yz.getElement()) && valno >= yz.getMin() && valno <= yz.getMax()) {
                        city.setNoRainDay(yz.getYz());
                    } else if ("日降水量".equals(yz.getElement()) && valRain >= yz.getMin() && valRain <= yz.getMax()) {
                        city.setYbRain(yz.getYz());
                    }
                }
                sumYz = (int) (city.getYbMaxTemp() + city.getYbMinRelHumidity() + city.getYbMaxWindS() + city.getNoRainDay() + city.getYbRain());
                insertData.setStationid(city.getId());
                insertData.setForcastdate(timestamp1); // 根据实际情况调整日期转换
                insertData.setHumidity(city.getYbMinRelHumidity());
                insertData.setNoraincomponent(city.getNoRainDay());
                insertData.setTempcomponent(city.getYbMaxTemp());
                insertData.setWindcomponent(city.getYbMaxWindS());
                insertData.setRaincomponent(city.getYbRain());
                insertData.setFireindex(sumYz);
                insertData.setFirelevel(getFireLevel(sumYz));
                insertData.setLon(city.getLon());
                insertData.setLat(city.getLat());
                insertData.setStationname(city.getName());
                // 将生成的数据保存到数据库
                int insert = cshxZsybMapper.insert(insertData);
                System.err.println("insert : " + insert);
                insertListData.add(insertData);
            }
            System.err.println("insertListData : " + insertListData.size());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return insertListData;
    }


    @Override
    public int selectByNameOfProduct(String productName) {
        BaseProduct baseProduct = baseProductMapper.selectOne(new LambdaQueryWrapper<BaseProduct>()
                .eq(BaseProduct::getProductname, productName));
        return baseProduct.getId();
    }

    @Override
    public Object   forecastRelease(String date, String userName, MultipartFile[] images) throws ParseException {
        //模板路径
        String templatePath;
        //产品路径
        String targetPath;
        //pdf路径
        String targetPdfPath = null;

        ApplicationHome applicationHome = new ApplicationHome(this.getClass());
        if (active.equals("dev")) {
            templatePath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() +
                    "\\src\\main\\resources\\templates\\cshxTemp\\城市火险等级预报模板.docx";
            targetPath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() +
                    "\\src\\main\\resources\\temp\\城市火险等级.docx";
            targetPdfPath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() +
                    "\\src\\main\\resources\\temp\\城市火险等级.pdf";
        } else {
            templatePath = applicationHome.getSource().getParentFile() +
                    "\\resource\\templates\\cshxTemp\\城市火险等级预报模板.docx";
            targetPath = applicationHome.getSource().getParentFile() +
                    "\\resources\\temp\\城市火险等级.docx";
            targetPdfPath = applicationHome.getDir().getParentFile().getParentFile().getAbsolutePath() +
                    "\\src\\main\\resources\\temp\\城市火险等级.pdf";
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日");
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日HH时");

        Date ybData = sdf.parse(date);
        String ybTimeStr = sdf1.format(ybData);
        String nowTimeStr = sdf2.format(new Date());

        String _WarnLevel = "一级";

        //生成文档
        try (
                InputStream templateInputStream = new FileInputStream(templatePath);
                OutputStream targetOutputStream = new FileOutputStream(targetPath);
                XWPFDocument document = new XWPFDocument(templateInputStream);
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                ByteArrayOutputStream byteArrayOutputStream1 = new ByteArrayOutputStream();
                ByteArrayOutputStream byteArrayOutputStream2 = new ByteArrayOutputStream()
        ) {
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            //段落替换
            String[] placeholders = new String[]{"[0]", "[1]", "[2]"};
            //替换内容
            String[] replacements = new String[]{userName, ybTimeStr, nowTimeStr};

            for (int i = 0; i < paragraphs.size(); i++) {
                XWPFParagraph paragraph = paragraphs.get(i);
                String text = paragraph.getText();

                replaceTextInParagraph(paragraph, placeholders, replacements);

                //插入图片
                if (StringUtils.isNotBlank(text) && text.contains("[图片]")) {
                    //获取下标
                    XmlCursor cursor = paragraph.getCTP().newCursor();
                    XWPFParagraph newPara = document.insertNewParagraph(cursor);
                    newPara.setAlignment(ParagraphAlignment.CENTER);//居中
                    XWPFRun newParaRun = newPara.createRun();
                    for (MultipartFile image : images) {
                        //插入图片
                        newParaRun.addPicture(image.getInputStream(), XWPFDocument.PICTURE_TYPE_PNG, "image.png,", Units.toEMU(300), Units.toEMU(300));
                    }
                    document.removeBodyElement(document.getPosOfParagraph(paragraph));
                }

                //插入等级预报数据表格
                LocalDateTime localDateTime = DateUtil.stringToLocalDateTime(date);
                Timestamp timestamp = DateUtil.localDateTimeToTimestamp(localDateTime);
                List<CshxZsyb> list = cshxZsybMapper.getList(timestamp);
                if (StringUtils.isNotBlank(text) && text.contains("城市火险") && list.size() > 0) {

                    //获取下标
                    XmlCursor cursor = paragraph.getCTP().newCursor();
//                    cursor.toNext
                    XWPFTable table = document.insertNewTbl(cursor);
                    //添加表头
                    XWPFTableRow row_0 = table.getRow(0);
                    row_0.getCell(0).setText("站点名称");
                    row_0.addNewTableCell().setText("湿度分量");
                    row_0.addNewTableCell().setText("无降水日分量");
                    row_0.addNewTableCell().setText("温度分量");
                    row_0.addNewTableCell().setText("风力分量");
                    row_0.addNewTableCell().setText("降水分量");
                    row_0.addNewTableCell().setText("火险指数");
                    row_0.addNewTableCell().setText("火险等级");
                    for (CshxZsyb yb : list) {
                        //插入图层表格数据
                        XWPFTableRow dataRow = table.createRow();
                        dataRow.getCell(0).setText(yb.getStationname());
                        dataRow.getCell(1).setText(String.valueOf(yb.getHumidity()));
                        dataRow.getCell(2).setText(String.valueOf(yb.getNoraincomponent()));
                        dataRow.getCell(3).setText(String.valueOf(yb.getTempcomponent()));
                        dataRow.getCell(4).setText(String.valueOf(yb.getWindcomponent()));
                        dataRow.getCell(5).setText(String.valueOf(yb.getRaincomponent()));
                        dataRow.getCell(6).setText(String.valueOf(yb.getFireindex()));
                        dataRow.getCell(7).setText(yb.getFirelevel());
                    }
                    setTableLocation(table, "center");
                    setCellLocation(table, "CENTER", "center");
                }

                //插入重要地点数据表格
                Map<String, String> map = new HashMap<>();
                List<String> strid = new ArrayList<>();
                for (CshxZsyb yb : list) {
                    strid.add(yb.getStationname());
                    map.put(yb.getStationname(), yb.getFirelevel());
                    _WarnLevel = yb.getFirelevel();
                }
                // 提前处理空值情况
                List<CcshxImpDot> list2=new ArrayList<>();
                if (!strid.isEmpty()) {
                    list2 = ccshxImpDotMapper.selectByStationNames(strid);
                }
                if (StringUtils.isNotBlank(text) && text.contains("【重要地点火险等级预报】") && list2.size() > 0) {
                    //获取下标
                    XmlCursor cursor = paragraph.getCTP().newCursor();
                    XWPFTable table = document.insertNewTbl(cursor);
                    //添加表头
                    XWPFTableRow row_0 = table.getRow(0);
                    row_0.getCell(0).setText("重要地点");
                    row_0.addNewTableCell().setText("联系电话");
                    row_0.addNewTableCell().setText("附近地点");
                    row_0.addNewTableCell().setText("火险等级");
                    //插入图层表格数据
                    for (CcshxImpDot dot : list2) {
                        //插入图层表格数据
                        XWPFTableRow dataRow = table.createRow();
                        dataRow.getCell(0).setText(dot.getName());
                        dataRow.getCell(1).setText(dot.getTel());
                        dataRow.getCell(2).setText(dot.getJoinstation());
                        dataRow.getCell(3).setText(map.get(dot.getJoinstation()) == "" ? "1" : map.get(dot.getJoinstation()));
                    }
                    setTableLocation(table, "center");
                    setCellLocation(table, "CENTER", "center");
                    document.removeBodyElement(document.getPosOfParagraph(paragraph));

                }

            }
            // 将生成的文档保存到输出文件
            document.write(targetOutputStream);

            String context = String.format("{0}气象局{1}发布最新城市火险预报：全市范围内城市火险最高等级（{2}）", county, date, _WarnLevel);//

            //获取文档名称
            String productName = ybTimeStr + "城市火险等级预报产品.docx";
            //保存基本产品表数据
            BaseProduct baseProduct = new BaseProduct();
            baseProduct.setProductname(productName);
            baseProduct.setProducttype("城市火险预报");
            baseProduct.setForecasttime(ybData);
            baseProduct.setMaketime(new Date());
            baseProduct.setContext(context);
            baseProduct.setMaker(userName);
            baseProductMapper.insert(baseProduct);
            byte[] buffer = new byte[1024];
            int bytesRead;
            FileInputStream inputStream = new FileInputStream(targetPath);
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            }
            byte[] byteArray = byteArrayOutputStream.toByteArray();
            wordToPdf(targetPath, targetPdfPath);
            //保存到mongodb库中
            // HyDocFile hyDocFile = new HyDocFile();
            // hyDocFile.setData(byteArray);
            // hyDocFile.setTable_name("base_product");
            // hyDocFile.setId(String.valueOf(baseProduct.getId()));
            // mongoTemplate.save(hyDocFile);
            //pdf入库
            byte[] buffer1 = new byte[1024];
            int bytesRead1 ;
            FileInputStream inputStream1 = new FileInputStream(targetPdfPath);
            while ((bytesRead1 = inputStream1.read(buffer1)) != -1) {
                byteArrayOutputStream1.write(buffer1, 0, bytesRead1);
            }

            byte[] bytes = byteArrayOutputStream1.toByteArray();
            Map<String, Object> map2 = new HashMap<String, Object>();
            map2.put("id", String.valueOf(baseProduct.getId()));
            map2.put("data", bytes);
            map2.put("table_name", "base_product");
            map2.put("collectionName", "pdf_file");
            map2.put("advCode", "451027");
            ms.insertData(map2);
            //图片
            for (MultipartFile image : images) {
                //插入图片
                InputStream inputStream2 = image.getInputStream();
                byte[] buffer2 = new byte[1024];
                int bytesRead2;
                while ((bytesRead2 = inputStream2.read(buffer2)) != -1) {
                    byteArrayOutputStream2.write(buffer2, 0, bytesRead2);
                }
                byte[] bytes2 = byteArrayOutputStream2.toByteArray();
                Map<String, Object> map3 = new HashMap<String, Object>();
                map3.put("id", String.valueOf(baseProduct.getId()));
                map3.put("data", bytes2);
                map3.put("table_name", "base_product");
                map3.put("collectionName", "image_file");
                map3.put("advCode", "451027");
                ms.insertData(map3);
            }
            // 设置前端响应
            HttpHeaders headers = new HttpHeaders();
            headers.setContentDispositionFormData("attachment", "城市火险等级预报产品.docx");
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentLength(byteArray.length);
            return new ResponseEntity<>(byteArray, headers, HttpStatus.OK);

        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("文档生成失败");
        }
        return null;


    }

    // 计算自动站指数信息
    private void CalcSmallScaleStationFactor(String timeChar, Timestamp timestamp) {
        // 城区的范围
        List<DmMapPoint> cityPointsWGS = YuLinCityPoints.getCityPointsWGS(YuLinCityPoints.yulinshi);
        List<TownshipForecast> townshipForecasts = townshipForecastMapper.selectByDatecharAndTimeChar(timeChar, timestamp);
        cityPointsWGS.remove(cityPointsWGS.size() - 1);
        for (TownshipForecast townshipForecast : townshipForecasts) {
            boolean b = MapCommon.pointWithinPolygon(cityPointsWGS, townshipForecast.getLongitude(), townshipForecast.getLatitude());
            if (b) {
                CityFire city = new CityFire();
                city.setName(townshipForecast.getStationname().trim());
                city.setId(townshipForecast.getStationid().trim());
                city.setLon(townshipForecast.getLongitude());
                city.setLat(townshipForecast.getLatitude());
                city.setYbMinRelHumidity(townshipForecast.getHumid());
                city.setYbMaxTemp(townshipForecast.getMaxtemp());
                city.setYbMaxWindS(townshipForecast.getWinds());
                city.setYbRain(townshipForecast.getRain());
                citys.add(city);
            }
        }
    }

    // 计算特殊站点信息
    private void CalcSpecialStationFactor(String timeChar, Timestamp timestamp) {
        List<TourFcst> list = tourFcstMapper.selectByDatecharAndTimeChar(timeChar, timestamp);
        if (list.size() > 0) {
            for (TourFcst tourFcst : list) {
                CityFire city = new CityFire();
                city.setName(tourFcst.getStationname().trim());
                city.setId(tourFcst.getStationid().trim());
                city.setLon(tourFcst.getLongitude());
                city.setLat(tourFcst.getLatitude());
                city.setYbMinRelHumidity(tourFcst.getHumid());
                city.setYbMaxTemp(tourFcst.getMaxtemp());
                city.setYbMaxWindS(Double.parseDouble(tourFcst.getWinds()));
                city.setYbRain(tourFcst.getRain());
                citys.add(city);
            }
        } else {
            System.out.println("计算特殊站点信息失败！！！");
        }
    }

    // 获取因子
    private List<CSHX_yz> loadYz(LocalDateTime localDateTime) {
        int month = localDateTime.getMonthValue();
        String condition = "";
        if (month >= 3 && month <= 5)
            condition = "3,5";
        else if (month >= 6 && month <= 8)
            condition = "6,8";
        else if (month >= 9 && month <= 11)
            condition = "9,11";
        else
            condition = "12,2";
        List<CshxYz> list = cshxYzMapper.selectList(condition);
        List<CSHX_yz> listA = new ArrayList<>();
        if (list.size() != 0) {
            for (CshxYz cshxYz : list) {
                if (cshxYz.getMonth() != null && cshxYz.getMonth() != condition && !cshxYz.getMonth().isEmpty()) {
                    continue;

                } else {
                    CSHX_yz yz = new CSHX_yz();
                    yz.setElement(cshxYz.getWeatherfactor().trim());
                    yz.setMax(cshxYz.getMaxvalue());
                    yz.setMin(cshxYz.getMinvalue());
                    yz.setYz(Integer.valueOf(cshxYz.getExponentialcomponent()));
                    listA.add(yz);
                }
            }
        }
        return listA;
    }

    // 火险等级
    private String getFireLevel(int yz) {
        List<CshxSetting> list = cshxSettingMapper.selectList(null);
        if (yz <= list.get(0).getValue())
            return "1级";
        else if (yz >= (list.get(0).getValue() + 1) && yz <= list.get(1).getValue())
            return "2级";
        else if (yz >= (list.get(1).getValue() + 1) && yz <= list.get(2).getValue())
            return "3级";
        else if (yz >= (list.get(2).getValue() + 1) && yz <= list.get(3).getValue())
            return "4级";
        else
            return "5级";

    }


    @Override
    public String fireProneAreas(final String forecastDate) {
        List<CshxZsyb> cshxZsybList = cshxZsybMapper.queryByForecastDate(DateUtil.localDateTimeToTimestamp(DateUtil.stringToLocalDateTime(forecastDate)));
        List<CshxSetting> cshxSettings = cshxSettingMapper.selectAll();
        if (cshxZsybList.size() > 1) {
            String txt = TxtFileManager.urbanFireInsuranceToTxt(cshxZsybList, cshxSettings);
            try {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
                // 生成文件名，格式为时间+RefinedForecastingController
                String txtName = dateFormat.format(new Date()) + "CshxHxyjServiceImpl";
                //写入文件
                String txtPath = txtFileManager.writeDataToTxtFile(txt, txtName);
                //文件夹目录
                String homePath = TxtFileManager.extractFolderPath(txtPath);
                // 一小时删除任务
                TxtFileManager.cleanupTempFiles(homePath, 3600000);

                System.err.println("文件存储路径：" + txtPath);

                String url = "http://" + txtIp + ":" + txtPort + path + "/" + txtName + ".txt";
                System.err.println(url);

                DmServiceConnector conn = new DmServiceConnector(serverName, port);
                String callPlugin = conn.getCallPlugin(pluginClassFullName, methodName, url);
                //System.err.println(callPlugin);
                return callPlugin;

            } catch (IOException e) {
                e.printStackTrace();
                return "Error writing file.";
            }
        } else {
            return "数据少于两条，无法生成";
        }
    }

}
